package org.planx.xmlstore.routing;

import java.io.*;
import java.net.*;
import java.util.*;
import junit.framework.*;

public class SpaceTest extends RoutingTestCase {
    private static final String PATH = "test/org/planx/xmlstore/routing/";
    private Node local;
    private Configuration conf;

    public SpaceTest(String s) {
        super(s);
    }

    public static Test suite() {
        return new TestSuite(SpaceTest.class);
    }

    public static void main(String args[]) {
        junit.textui.TestRunner.run(SpaceTest.class);
    }

    protected void setUp() {
        try {
            Identifier.IDSIZE = 4;
            conf = new Configuration();
            conf.B = 1;
            conf.K = 2;
            conf.RCSIZE = 1;
            conf.STALE = 1;
            local = new Node(InetAddress.getLocalHost(), 4000,
                               Identifier.randomIdentifier());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Tests space tree structure when inserting all nodes in order of
     * increasing distance.
     **/
    public void testInsert1() throws IOException {
        conf.B = 1;
        conf.K = 1;
        conf.RCSIZE = 1;
        Space s = new Space(local, conf);
        for (int id=0; id<=15; id++) s.insertNode(newXorNode(local,id));
        assertEquals(readFile(PATH+"SpaceTest1.out"), s.toString());
    }

    /**
     * Tests space tree structure when inserting all nodes in order of
     * decreasing distance and compactifying the tree.
     **/
    public void testInsert2() throws IOException {
        conf.B = 1;
        conf.K = 1;
        conf.RCSIZE = 1;
        Space s = new Space(local, conf);
        for (int id=15; id>=0; id--) s.insertNode(newXorNode(local,id));
        for (int id=15; id>=0; id--) s.insertNode(newXorNode(local,id));
        assertEquals(readFile(PATH+"SpaceTest2.out"), s.toString());
    }

    /**
     * Tests space tree structure with bucket size greater than 1.
     **/
    public void testInsert3() throws IOException {
        conf.B = 1;
        conf.K = 3;
        conf.RCSIZE = 1;
        Space s = new Space(local, conf);
        for (int id=0; id<=15; id++) s.insertNode(newXorNode(local,id));
        assertEquals(readFile(PATH+"SpaceTest3.out"), s.toString());
    }

    /**
     * Tests compactification with bucket size greater than 1.
     **/
    public void testInsert4() throws IOException {
        conf.B = 1;
        conf.K = 3;
        conf.RCSIZE = 1;
        Space s = new Space(local, conf);
        for (int id=15; id>=0; id--) s.insertNode(newXorNode(local,id));
        for (int id=15; id>=0; id--) s.insertNode(newXorNode(local,id));
        assertEquals(readFile(PATH+"SpaceTest4.out"), s.toString());
    }

    public void testClosestNodes1() throws IOException {
        conf.B = 1;
        conf.K = 1;
        conf.RCSIZE = 1;
        Space s = new Space(local, conf);
        for (int id=0; id<=15; id++) s.insertNode(newXorNode(local,id));
        assertEquals("[1000]", toXorNodeString(local,getClosestOrdered(
                                               s,newXorId(local,15))));
        assertEquals("[1000]", toXorNodeString(local,getClosestOrdered(
                                               s,newXorId(local,8))));
        assertEquals("[0100]", toXorNodeString(local,getClosestOrdered(
                                               s,newXorId(local,7))));
        assertEquals("[0100]", toXorNodeString(local,getClosestOrdered(
                                               s,newXorId(local,4))));
        assertEquals("[0010]", toXorNodeString(local,getClosestOrdered(
                                               s,newXorId(local,3))));
        assertEquals("[0010]", toXorNodeString(local,getClosestOrdered(
                                               s,newXorId(local,2))));
        assertEquals("[0001]", toXorNodeString(local,getClosestOrdered(
                                               s,newXorId(local,1))));
        assertEquals("[0000]", toXorNodeString(local,getClosestOrdered(
                                               s,newXorId(local,0))));
    }

    public void testClosestNodes2() throws IOException {
        conf.B = 1;
        conf.K = 3;
        conf.RCSIZE = 1;
        Space s = new Space(local, conf);
        for (int id=0; id<=15; id++) s.insertNode(newXorNode(local,id));
        assertEquals("[1010,1001,1000]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,15))));
        assertEquals("[1000,1001,1010]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,8))));
        assertEquals("[0110,0101,0100]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,7))));
        s.removeNode(newXorNode(local,6)); // 0111 is moved into bucket from cache
        assertEquals("[0111,0101,0100]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,7))));
        s.removeNode(newXorNode(local,7)); // bucket now only contains 2 entries
        assertEquals("[0101,0100,0011]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,7))));
    }

    /**
     * Test structure with larger B
     **/
    public void testLogExponent() throws IOException {
        conf.B = 2;
        conf.K = 1;
        conf.RCSIZE = 1;
        Space s = new Space(local, conf);
        for (int id=15; id>=0; id--) s.insertNode(newXorNode(local,id));
        for (int id=15; id>=0; id--) s.insertNode(newXorNode(local,id));
        assertEquals(readFile(PATH+"SpaceTest5.out"), s.toString());
    }

    /**
     * Tests that a node is removed when it has been attempted to be
     * removed STALE times.
     **/
    public void testStaleCount() throws IOException {
        conf.B = 1;
        conf.K = 2;
        conf.RCSIZE = 1;
        conf.STALE = 3;
        Space s = new Space(local, conf);
        boolean res;
        s.insertNode(newXorNode(local,7));
        assertEquals("[0000,0111]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,1))));
        res = s.removeNode(newXorNode(local,7));
        assertFalse(res);
        assertEquals("[0000,0111]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,1))));
        res = s.removeNode(newXorNode(local,7));
        assertFalse(res);
        assertEquals("[0000,0111]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,1))));
        res = s.removeNode(newXorNode(local,7));
        assertTrue(res);
        assertEquals("[0000]",
            toXorNodeString(local,getClosestOrdered(s,newXorId(local,1))));
    }
}
